﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using TL_Cloud.API.Helpers;
using TL_Cloud.Common;
using TL_Cloud.Core;
using TL_Cloud.Core.Entities;
using TL_Cloud.Core.Extensions;
using TL_Cloud.Core.Interfaces;
using TL_Cloud.Core.LinkURL;
using TL_Cloud.Core.Services;
using TL_Cloud.DbRepositoryInterface.BookShop;
using TL_Cloud.Models.BookShop;
using TL_Cloud.ViewModels.BookShop;

namespace TL_Cloud.API.Controllers
{
    /// <summary>
    /// 年级信息
    /// </summary>
    [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class GradesController : ControllerBase
    {
        private readonly ILogger logger;
        private readonly IUnitOfWork _unitOfWork;
        private readonly IBaseGradeRepository _gradeRepository;
        private readonly ITypeHelperService _typeHelperService;
        private readonly IPropertyMappingContainer _propertyMappingContainer = null;
        private readonly IMapper _mapper;
        private readonly IUrlHelper _urlHelper;

        public GradesController(IMapper mapper, 
            ILogger<GradesController> logger,
            ITypeHelperService typeHelperService,
            IPropertyMappingContainer propertyMappingContainer,
            IBaseGradeRepository gradeRepository,
            IUnitOfWork unitOfWork,
            IUrlHelper urlHelper
            )
        {
            this._mapper = mapper;
            this.logger = logger;
            this._typeHelperService = typeHelperService;
            this._gradeRepository = gradeRepository;
            this._urlHelper = urlHelper;
            this._propertyMappingContainer = propertyMappingContainer;
            this._unitOfWork = unitOfWork;
        }
        /// <summary>
        /// 获取所有的年级信息
        /// </summary>
        /// <param name="gradeParameters"></param>
        /// <returns></returns>
        // GET api/values
        [HttpGet(Name = "GetGrades")]
        public async Task<IActionResult> Get([FromQuery]GradeQueryParameters gradeParameters)
        {

            //判断排序是否存在 ，
            if (!_propertyMappingContainer.ValidateMappingExistsFor<BaseGradeResource, Base_GradeInfo>(gradeParameters.OrderBy))
            {
                return BadRequest("Can't finds fields for sorting.");
            }

            //判断fields参数是否在制定的类型中存在
            if (!_typeHelperService.TypeHasProperties<BaseGradeResource>(gradeParameters.Fields))
            {
                return BadRequest("Fields not exist.");
            }

            var gradeList = await _gradeRepository.GetAllEntitiesAsync(gradeParameters);

            var gradeResources = _mapper.Map<IEnumerable<Base_GradeInfo>, IEnumerable<BaseGradeResource>>(gradeList);

            //生成 下一个连接和上一个连接的url
            var previousPageLink = gradeList.HasPrevious ?
                new LinkUrlCreater<GradeQueryParameters>(_urlHelper).CreateGetUrl("GetGrades", gradeParameters,
                    PaginationResourceUriType.PreviousPage) : null;

            var nextPageLink = gradeList.HasNext ?
               new LinkUrlCreater<GradeQueryParameters>(_urlHelper).CreateGetUrl("GetGrades", gradeParameters,
                    PaginationResourceUriType.NextPage) : null;


            //数据返回分页数据
            var meta = new
            {
                gradeList.TotalItemsCount,
                gradeList.PageSize,
                gradeList.PageIndex,
                gradeList.PageCount,
                previousPageLink,
                nextPageLink
            };

            Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(meta, new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver()
            }));
            //返回结果塑性
            return Ok(gradeResources.ToDynamicIEnumerable(gradeParameters.Fields));
        }
               
        /// <summary>
        /// 获取单个年级
        /// </summary>
        /// <param name="id"></param>
        /// <param name="fields"></param>
        /// <returns></returns>
        [HttpGet("{id}", Name = "GetGrade")]
        public async Task<IActionResult> Get(string id, string fields = null)
        {
            if (!_typeHelperService.TypeHasProperties<BaseGradeResource>(fields))
            {
                return BadRequest("Fields not exist.");
            }
            var grade = await _gradeRepository.GetEntityByIdAsync(id);

            if (grade == null)
            {
                return NotFound();
            }

            var gradeResource = _mapper.Map<Base_GradeInfo, BaseGradeResource>(grade);
            var shapedGradeResource = gradeResource.ToDynamic(fields);
            var links = new LinkUrlCreater<GradeQueryParameters>(_urlHelper).CreateLinksForPost("GetGrade", "DeleteGrade", id, fields);
            var result = (IDictionary<string, object>)shapedGradeResource;
            result.Add("links", links);

            return Ok(result);
        }

        /// <summary>
        /// 增加年级数据
        /// </summary> 
        [HttpPost(Name = "CreateGrade")]
        public async Task<IActionResult> Post([FromBody] BaseGradeAddResource gradeAddResource)
        {
            if (gradeAddResource == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }

            var newGrade = _mapper.Map<BaseGradeAddResource, Base_GradeInfo>(gradeAddResource);
            var userinfo = this.GetUserInfo();
            newGrade.Create(userinfo.Item1, userinfo.Item2);

            _gradeRepository.Add(newGrade);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception("Save Failed!");
            }

            var resultResource = _mapper.Map<Base_GradeInfo, BaseGradeResource>(newGrade);

            var links = new LinkUrlCreater<GradeQueryParameters>(_urlHelper).CreateLinksForPost("GetGrade", "DeleteGrade", newGrade.GradeId);
            var linkedPostResource = resultResource.ToDynamic() as IDictionary<string, object>;
            linkedPostResource.Add("links", links);
            return CreatedAtRoute("GetGrade", new { id = linkedPostResource["GradeId"] }, linkedPostResource);
        }

        /// <summary>
        /// 修改年级数据
        /// </summary>
        /// <param name="id"></param> 
        [HttpPut("{id}", Name = "UpdateGrade")]
        public async Task<IActionResult> UpdatePost(string id, [FromBody] BaseGradeUpdateResource gradeUpdate)
        {
            if (gradeUpdate == null)
            {
                return BadRequest();
            }

            if (!ModelState.IsValid)
            {
                return new MyUnprocessableEntityObjectResult(ModelState);
            }

            var grade = await _gradeRepository.GetEntityByIdAsync(id);
            if (grade == null)
            {
                return NotFound();
            }
            _mapper.Map(gradeUpdate, grade);
            var userinfo = this.GetUserInfo();
            grade.Modify(userinfo.Item1,userinfo.Item2);  

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Updating grade {id} failed when saving.");
            }
            return NoContent();
        }

        /// <summary>
        /// 删除数据
        /// </summary> 
        /// <returns></returns>
        [HttpDelete("{id}", Name = "DeleteGrade")]
        public async Task<IActionResult> DeleteGrade(string id)
        {
            var post = await _gradeRepository.GetEntityByIdAsync(id);
            if (post == null)
            {
                return NotFound();
            }

            _gradeRepository.Delete(post);

            if (!await _unitOfWork.SaveAsync())
            {
                throw new Exception($"Deleting Grade {id} failed when saving.");
            }

            return NoContent();
        }
    }
}
